/**
 *
 * User: Zhikang.Peng
 * Date: 2018/06/20 15:11
 */
package loads

import (
	"gitee.com/thghh/jvmgo/instructions/base"
	"gitee.com/thghh/jvmgo/rtda"
	"gitee.com/thghh/jvmgo/rtda/heap"
)

//将int型数组指定索引的值推送至栈顶
type IALOAD struct{ base.NoOperandsInstruction }

func (self *IALOAD) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	// 数组索引
	index := stack.PopInt()
	// 数组引用
	arrRef := stack.PopReference()

	checkNotNil(arrRef)
	refs := arrRef.Ints()
	checkIndex(len(refs), index)
	stack.PushInt(refs[index])
}

//将long型数组指定索引的值推送至栈顶
type LALOAD struct{ base.NoOperandsInstruction }

func (self *LALOAD) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	// 数组索引
	index := stack.PopInt()
	// 数组引用
	arrRef := stack.PopReference()

	checkNotNil(arrRef)
	refs := arrRef.Longs()
	checkIndex(len(refs), index)
	stack.PushLong(refs[index])
}

//将float型数组指定索引的值推送至栈顶
type FALOAD struct{ base.NoOperandsInstruction }

func (self *FALOAD) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	// 数组索引
	index := stack.PopInt()
	// 数组引用
	arrRef := stack.PopReference()

	checkNotNil(arrRef)
	refs := arrRef.Floats()
	checkIndex(len(refs), index)
	stack.PushFloat(refs[index])
}

//将double型数组指定索引的值推送至栈顶
type DALOAD struct{ base.NoOperandsInstruction }

func (self *DALOAD) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	// 数组索引
	index := stack.PopInt()
	// 数组引用
	arrRef := stack.PopReference()

	checkNotNil(arrRef)
	refs := arrRef.Doubles()
	checkIndex(len(refs), index)
	stack.PushDouble(refs[index])
}

//将引用型数组指定索引的值推送至栈顶
type AALOAD struct{ base.NoOperandsInstruction }

func (self *AALOAD) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	index := stack.PopInt()
	arrRef := stack.PopReference()
	checkNotNil(arrRef)
	refs := arrRef.References()
	checkIndex(len(refs), index)
	stack.PushReference(refs[index])
}

//将boolean或byte型数组指定索引的值推送至栈顶
type BALOAD struct{ base.NoOperandsInstruction }

func (self *BALOAD) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	// 数组索引
	index := stack.PopInt()
	// 数组引用
	arrRef := stack.PopReference()

	checkNotNil(arrRef)
	refs := arrRef.Bytes()
	checkIndex(len(refs), index)
	stack.PushInt(int32(refs[index]))
}

//将char型数组指定索引的值推送至栈顶
type CALOAD struct{ base.NoOperandsInstruction }

func (self *CALOAD) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	// 数组索引
	index := stack.PopInt()
	// 数组引用
	arrRef := stack.PopReference()

	checkNotNil(arrRef)
	refs := arrRef.Chars()
	checkIndex(len(refs), index)
	stack.PushInt(int32(refs[index]))
}

//将short型数组指定索引的值推送至栈顶
type SALOAD struct{ base.NoOperandsInstruction }

func (self *SALOAD) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	// 数组索引
	index := stack.PopInt()
	// 数组引用
	arrRef := stack.PopReference()

	checkNotNil(arrRef)
	refs := arrRef.Shorts()
	checkIndex(len(refs), index)
	stack.PushInt(int32(refs[index]))
}

// 检查数组对象是否为空
func checkNotNil(ref *heap.Object) {
	if ref == nil {
		panic("java.lang.NullPointerException")
	}
}

// 检查数组下标是否越界
func checkIndex(arrLen int, index int32) {
	if index < 0 || index >= int32(arrLen) {
		panic("java.lang.ArrayIndexOutBoundException")
	}
}
